#pragma once

namespace bit
{
	template<class T>
	struct ListNode
	{
		ListNode<T>* _next;
		ListNode<T>* _prev;
		T _date;

		ListNode(const T& pos = T())
		{
			_next = nullptr;
			_prev = nullptr;
			_date = pos;
		}

	};

	template<class T1,class T2 = T1>
	struct ListIterator
	{
		typedef ListIterator<T1,T2> iterator;
		typedef ListNode<T1> node;
		node* _node;

		ListIterator(node* pos)
		{
			_node = pos;
		}

		T2& operator*()
		{
			return _node->_date;
		}

		iterator operator++()
		{
			_node = _node->_next;
			return _node;
		}		

		iterator operator++(int)
		{
			_node = _node->_next;
			return _node->_prev;
		}

		iterator operator--()
		{
			_node = _node->_prev;
			return _node;
		}
		iterator operator--(int)
		{
			_node = _node->_prev;
			return _node->_next;
		}

		T2* operator->()
		{
			return &_node->_date;
		}

		bool operator!=(iterator pos)
		{
			return _node != pos._node;
		}
	};

	template<class T>
	class list
	{

	public:
		typedef ListNode<T> node;
		typedef ListIterator<T> iterator;
		typedef ListIterator<T,const T> const_iterator;
		list()
			:_node(new node)
		{
			_node->_next = _node;
			_node->_prev = _node;
		}

		void push_back(const T& x)
		{
			node* head = _node;
			node* tail = _node->_prev;
			node* p = new node(x);
			tail->_next = p;
			p->_prev = tail;
			p->_next = head;
			head->_prev = p;
		}

		void pop_back()
		{
			assert(_node != _node->_next);
			node* head = _node;
			node* tail = head->_prev;
			node* newtail = tail->_prev;
			newtail->_next = head;
			head->_prev = newtail;
			delete[] tail;
		}

		iterator begin()
		{
			return iterator(_node->_next);
		}

		const_iterator begin()const
		{
			return const_iterator(_node->_next);
		}

		iterator end()
		{
			return iterator(_node);
		}

		const_iterator end()const
		{
			return const_iterator(_node);
		}

		void push_front(const T& x)
		{
			node* newnode = new node(x);
			node* head = _node;
			node* tail = _node->_next;
			head->_next = newnode;
			newnode->_prev = head;
			newnode->_next = tail;
			tail->_prev = newnode;
		}

		void pop_front()
		{
			assert(_node != _node->_next);
			node* head = _node;
			node* tail = _node->_next;
			head->_next = tail->_next;
			tail->_next->_prev = head;
			delete[]tail;
		}

		iterator insert(iterator pos,const T& x)
		{
			node* newnode = new node(x);
			node* next = pos._node;
			node* last = next->_prev;
			last->_next = newnode;
			newnode->_prev = last;
			newnode->_next = next;
			next->_prev = newnode;
			return iterator(newnode);
		}

		iterator erase(iterator pos)
		{
			assert(_node != _node->_next);
			node* self = pos._node;
			node* next = self->_next;
			node* last = self->_prev;
			last->_next = next;
			next->_prev = last;
			delete[] self;
			return iterator(next);
		}

	private:
		node* _node;
	};

	void test_list1()
	{
		list<int> l1;
		l1.push_back(10);
		l1.push_back(2);
		l1.push_back(3);
		//l1.pop_back();
		//l1.pop_back();
		//l1.pop_back();
		//l1.pop_back();
		list<int>::iterator it1 = l1.begin();
		//cout << *it1 << endl;
		while (it1 != l1.end())
		{
			cout << *it1 << ' ';
			*it1 += 10;
			it1++;
		}
		cout << endl;
		for (auto e : l1)
		{
			cout << e << ' ';
		}
	}



	void test_list2()
	{
		list<int> l1;
		l1.push_back(1);
		l1.push_back(2);
		l1.push_back(3);
		l1.push_back(4);
		l1.push_front(5);
		l1.push_front(6);
		l1.push_front(7);
		const list<int> l2 = l1;
		list<int>::const_iterator it2 = l2.begin();
		while (it2 != l2.end())
		{
			cout << *it2 << ' ';
			//*it2 += 10;
			it2++;
		}
		cout << endl;
		l1.pop_front();
		it2 = l2.begin();
		while (it2 != l2.end())
		{
			cout << *it2 << ' ';
			//*it2 += 10;
			it2++;
		}
	}

	struct A
	{
		int _row;
		int _col;
		A(int col = 90, int rol = 90)
			:_row(col)
			, _col(rol)
		{}
	};

	void test_list3()
	{
		list<A> l1;
		l1.push_back(A(101, 100));
		l1.push_back(A(202, 200));
		l1.push_back(A(303, 300));
		l1.push_back(A(404, 400));
		list<A>::iterator it1 = l1.begin();
		while (it1 != l1.end())
		{
			cout << it1->_row << ' ';
			it1++;
		}
		cout << endl;
		it1 = l1.begin();
		++it1;
		it1 = l1.insert(it1, A(5555, 6666));
		it1 = l1.begin();
		while (it1 != l1.end())
		{
			cout << it1->_row << ' ';
			it1++;
		}
		cout << endl;
		it1 = l1.begin();
		++it1; it1++;
		it1 = l1.erase(it1);
		it1 = l1.begin();
		while (it1 != l1.end())
		{
			cout << it1->_row << ' ';
			it1++;
		}
	}
}